package com.tyk.bookstore.back.product.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tyk.bookstore.back.common.core.model.type.BinVo;
import com.tyk.bookstore.back.common.core.model.type.SuggestionQuery;
import com.tyk.bookstore.back.common.core.util.AssertUtil;
import com.tyk.bookstore.back.common.core.util.IdGenerator;
import com.tyk.bookstore.back.common.core.util.ObjUtil;
import com.tyk.bookstore.back.product.manager.excel.model.PublisherExcelVo;
import com.tyk.bookstore.back.product.model.entity.BookDo;
import com.tyk.bookstore.back.product.model.entity.PublisherDo;
import com.tyk.bookstore.back.product.model.query.PublisherAddQuery;
import com.tyk.bookstore.back.product.model.query.PublisherPageQuery;
import com.tyk.bookstore.back.product.model.query.PublisherUpdateQuery;
import com.tyk.bookstore.back.product.model.result.PublisherResultEnum;
import com.tyk.bookstore.back.product.model.vo.PublisherPageVo;
import com.tyk.bookstore.back.product.model.vo.PublisherVo;
import com.tyk.bookstore.back.product.repository.BookRepository;
import com.tyk.bookstore.back.product.repository.PublisherRepository;
import com.tyk.bookstore.back.product.service.PublisherService;
import com.tyk.bookstore.back.product.util.MapStructProduct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigInteger;
import java.util.List;
import java.util.Set;

/**
 * @author tyk
 * @description 出版社管理
 */
@Service
@RequiredArgsConstructor
public class PublisherServiceImp implements PublisherService {

    private final PublisherRepository publisherRepository;
    private final MapStructProduct mapStructProduct;
    private final BookRepository bookRepository;

    @Override
    public PublisherVo getById(Long id) {
        PublisherDo publisher = publisherRepository.selectById(id);
        AssertUtil.notNull(publisher, PublisherResultEnum.PUBLISHER_NOT_FOUND);
        return mapStructProduct.toPublisherVo(publisher);
    }

    @Override
    public PublisherPageVo getPage(PublisherPageQuery query) {
        Page<PublisherDo> page = new Page<>(query.getPage(), query.getLimit());
        LambdaQueryWrapper<PublisherDo> wrapper = buildPageQueryWrapper(query);
        publisherRepository.selectPage(page, wrapper);
        return mapStructProduct.toPublisherPageVo(page);
    }


    @Override
    public void add(PublisherAddQuery query) {
        AssertUtil.isFalse(
                publisherRepository.exist1Eq(
                        PublisherDo::getName, query.getName(), PublisherDo.class
                ),
                PublisherResultEnum.PUBLISHER_ALREADY_EXISTS
        );
        PublisherDo publisher = mapStructProduct.toPublisherDo(query);
        publisher.setId(IdGenerator.id());
        publisherRepository.insert(publisher);
    }

    @Override
    public void updateById(PublisherUpdateQuery query) {
        AssertUtil.isTrue(
                publisherRepository.exist1Eq(
                        PublisherDo::getId, query.getId(), PublisherDo.class
                ),
                PublisherResultEnum.PUBLISHER_NOT_FOUND
        );
        AssertUtil.isFalse(
                publisherRepository.exist1Eq1Ne(
                        PublisherDo::getName, query.getName(),
                        PublisherDo::getId, query.getId(),
                        PublisherDo.class
                ),
                PublisherResultEnum.PUBLISHER_ALREADY_EXISTS
        );
        PublisherDo publisher = mapStructProduct.toPublisherDo(query);
        publisherRepository.updateById(publisher);
    }

    @Override
    public void deleteById(Long id) {
        // 出版社存在
        AssertUtil.isTrue(
                publisherRepository.exist1Eq(
                        PublisherDo::getId, id, PublisherDo.class
                ),
                PublisherResultEnum.PUBLISHER_NOT_FOUND
        );
        // 该出版社下不存在书籍
        AssertUtil.isFalse(
                bookRepository.exist1Eq(
                        BookDo::getPublisherId, id, BookDo.class
                ),
                PublisherResultEnum.PUBLISHER_HAS_BOOK
        );
        publisherRepository.deleteById(id);
    }

    @Override
    public void deleteBatchByIdSet(Set<Long> idSet) {
        AssertUtil.equal(
                publisherRepository.count1In(PublisherDo::getId, idSet, PublisherDo.class),
                (long) idSet.size(),
                PublisherResultEnum.PUBLISHER_NOT_FOUND
        );
        publisherRepository.deleteBatchIds(idSet);
    }

    @Override
    public List<BinVo> getSuggestionList(SuggestionQuery query) {
        return publisherRepository.selectSuggestionList(query.getKeyword());
    }

    @Override
    public List<BinVo> getNameVoList() {
        return publisherRepository
                .<BigInteger, String>selectBinList(PublisherDo::getId, PublisherDo::getName, PublisherDo.class)
                .stream().map(it -> new BinVo(it.getV1().longValue(), it.getV2())).toList();
    }

    @Override
    public List<PublisherExcelVo> getPublisherExcelVoList(PublisherPageQuery query) {
        LambdaQueryWrapper<PublisherDo> w = buildPageQueryWrapper(query);
        List<PublisherDo> doList = publisherRepository.selectList(w);
        return mapStructProduct.toPublisherExcelVoList(doList);
    }

    @Override
    public void savePublisherExcelVoList(List<PublisherExcelVo> publisherList) {
        List<PublisherDo> doList = mapStructProduct.toPublisherDoList(publisherList);
        doList.forEach(it -> it.setId(IdGenerator.id()));
        publisherRepository.insertBatch(doList);
    }


    /**
     * 构建分页查询Wrapper
     *
     * @param query 参数
     * @return Wrapper
     */
    private LambdaQueryWrapper<PublisherDo> buildPageQueryWrapper(PublisherPageQuery query) {
        LambdaQueryWrapper<PublisherDo> w = new LambdaQueryWrapper<>();

        w.eq(query.getId() != null, PublisherDo::getId, query.getId());

        w.like(ObjUtil.notBlank(query.getNameLike()), PublisherDo::getName, query.getNameLike());

        w.like(ObjUtil.notBlank(query.getKeyword()), PublisherDo::getDescription, query.getKeyword());

        w.orderBy(true, false, PublisherDo::getCreateTime);

        return w;
    }
}
